/* * Copyright (c) 2003 The Nutch Organization. All rights reserved. Use subject * to the conditions in http://www.nutch.org/LICENSE.txt. */ package net.nutch.plugin; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.logging.Logger; import net.nutch.util.LogFormatter; import org.dom4j.DocumentException; /** * The plugin repositority is a registry of all plugins. * * At system boot up a repositority is builded by parsing the mainifest files of * all plugins. Plugins that require not existing other plugins are not * registed. For each plugin a plugin descriptor instance will be created. The * descriptor represent all meta information about a plugin. So a plugin * instance will be created later when it is required, this allow lazy plugin * loading. * * @author joa23 */ public class PluginRepository { private static PluginRepository fInstance; private ArrayList fRegisteredPlugins; private HashMap fExtensionPoints; private HashMap fActivatedPlugins; public static final Logger LOG = LogFormatter .getLogger("net.nutch.plugin.PluginRepository"); /** * @see java.lang.Object#Object() */ private PluginRepository() throws MalformedURLException, IOException, DocumentException { fActivatedPlugins = new HashMap(); fExtensionPoints = new HashMap(); fRegisteredPlugins = getDependencyCheckedPlugins(PluginManifestParser .parsePluginFolder()); installCoreExtensionPoints(); installExtensions(fRegisteredPlugins); // TODO may be it make sense to check if all core extension points have // a coresponding plugin since run nutch with out all core plugins make // no sense. } /** * Intalls the extension points that are required to run nutch. */ private void installCoreExtensionPoints() { String[] coreExtensionPointIds = CoreExtensionPoints .getCoreExtensionPoints(); for (int i = 0; i < coreExtensionPointIds.length; i++) { String coreExtensionPointId = coreExtensionPointIds[i]; LOG.fine("install core extension point: " + coreExtensionPointId); // TODO Schema should be supported by core extension points as well. ExtensionPoint extensionPoint = new ExtensionPoint( coreExtensionPointId, coreExtensionPointId, null); fExtensionPoints.put(coreExtensionPointId, extensionPoint); } } /** * @param fRegisteredPlugins */ private void installExtensions(ArrayList pRegisteredPlugins) { for (int i = 0; i < pRegisteredPlugins.size(); i++) { PluginDescriptor descriptor = (PluginDescriptor) pRegisteredPlugins .get(i); Extension[] extensions = descriptor.getExtensions(); for (int j = 0; j < extensions.length; j++) { Extension extension = extensions[j]; String xpId = extension.getTargetPoint(); ExtensionPoint point = getExtensionPoint(xpId); if (point == null) throw new IllegalArgumentException("ExtensionPoint: " + xpId + " does not exist."); point.addExtension(extension); } } } /** * @param pLoadedPlugins * @return ArrayList */ private ArrayList getDependencyCheckedPlugins(ArrayList pLoadedPlugins) { ArrayList availablePlugins = new ArrayList(); for (int i = 0; i < pLoadedPlugins.size(); i++) { PluginDescriptor descriptor = (PluginDescriptor) pLoadedPlugins .get(i); String[] dependencyIDs = descriptor.getDependencies(); boolean available = true; for (int j = 0; j < dependencyIDs.length; j++) { String id = dependencyIDs[j]; if (!dependencyIsAvailabel(id, pLoadedPlugins)) { available = false; break; } } if (available) { availablePlugins.add(descriptor); ExtensionPoint[] points = descriptor.getExtenstionPoints(); for (int j = 0; j < points.length; j++) { ExtensionPoint point = points[j]; String xpId = point.getId(); fExtensionPoints.put(xpId, point); } } } return availablePlugins; } /** * @param id * @param pLoadedPlugins * @return boolean */ private boolean dependencyIsAvailabel(String id, ArrayList pLoadedPlugins) { if (pLoadedPlugins != null && id != null) { for (int i = 0; i < pLoadedPlugins.size(); i++) { PluginDescriptor descriptor = (PluginDescriptor) pLoadedPlugins .get(i); if (descriptor.getPluginId().equals(id)) { return true; } } } return false; } /** * Returns the singelton instance of the <code>PluginRepository</code> */ public static synchronized PluginRepository getInstance() { if (fInstance != null) return fInstance; try { fInstance = new PluginRepository(); } catch (MalformedURLException e) { LOG.fine(e.toString()); } catch (IOException e) { LOG.fine(e.toString()); } catch (DocumentException e) { LOG.fine(e.toString()); } return fInstance; } /** * Returns all registed plugin descriptors. * * @return PluginDescriptor[] */ public PluginDescriptor[] getPluginDescriptors() { return (PluginDescriptor[]) fRegisteredPlugins .toArray(new PluginDescriptor[fRegisteredPlugins.size()]); } /** * Returns the descriptor of one plugin identified by a plugin id. * * @param pPluginId * @return PluginDescriptor */ public PluginDescriptor getPluginDescriptor(String pPluginId) { for (int i = 0; i < fRegisteredPlugins.size(); i++) { PluginDescriptor descriptor = (PluginDescriptor) fRegisteredPlugins .get(i); if (descriptor.getPluginId().equals(pPluginId)) return descriptor; } return null; } /** * Returns a extension point indentified by a extension point id. * * @param xpId */ public ExtensionPoint getExtensionPoint(String pXpId) { return (ExtensionPoint) fExtensionPoints.get(pXpId); } /** * Returns a instance of a plugin. Plugin instances are cached. So a plugin * exist only as one instance. This allow a central management of plugin own * resources. * * After creating the plugin instance the startUp() method is invoked. The * plugin use a own classloader that is used as well by all instance of * extensions of the same plugin. This class loader use all exported * libraries from the dependend plugins and all plugin libraries. * * @param pDescriptor * @return Plugin * @throws PluginRuntimeException */ public Plugin getPluginInstance(PluginDescriptor pDescriptor) throws PluginRuntimeException { if (fActivatedPlugins.containsKey(pDescriptor.getPluginId())) return (Plugin) fActivatedPlugins.get(pDescriptor.getPluginId()); try { PluginClassLoader loader = pDescriptor.getClassLoader(); Class pluginClass = loader.loadClass(pDescriptor.getPluginClass()); Constructor constructor = pluginClass .getConstructor(new Class[]{PluginDescriptor.class}); Plugin plugin = (Plugin) constructor .newInstance(new Object[]{pDescriptor}); plugin.startUp(); fActivatedPlugins.put(pDescriptor.getPluginId(), plugin); return plugin; } catch (ClassNotFoundException e) { throw new PluginRuntimeException(e); } catch (InstantiationException e) { throw new PluginRuntimeException(e); } catch (IllegalAccessException e) { throw new PluginRuntimeException(e); } catch (NoSuchMethodException e) { throw new PluginRuntimeException(e); } catch (InvocationTargetException e) { throw new PluginRuntimeException(e); } } /* * (non-Javadoc) * * @see java.lang.Object#finalize() */ protected void finalize() throws Throwable { shotDownActivatedPlugins(); } /** * @throws PluginRuntimeException */ private void shotDownActivatedPlugins() throws PluginRuntimeException { Iterator iterator = fActivatedPlugins.keySet().iterator(); while (iterator.hasNext()) { String pluginId = (String) iterator.next(); Plugin object = (Plugin) fActivatedPlugins.get(pluginId); object.shutDown(); } } }